#include "server.h"
/****************************************************
 * Méthode qui contient le serveur de chat
 * **************************************************/
void run()
{
    struct sockaddr_in infoaddrClient;
    char buff[MAXLINE], buff2[MAXLINE], nickname[MAXLINE];
    int n, i, j, nb_fds;
    struct pollfd fds[LISTENQ];
    char** nicknames = (char**) malloc(sizeof (char*) *1);

    socklen_t lenClient = sizeof (infoaddrClient);

    fds[0].fd = myListen(); //le premier client est le serveur
    fds[0].events = POLLIN;
    fds[0].revents = 0;
    nb_fds = 1;
    printf("Listening socket fd locked always at position zero in array: %d\n", fds[0].fd);

    // Routine
    for (;;)
    {
        //affiche les fd de tous les clients à chaque event ou toutes les 30 sec
        for (i = 1; i < nb_fds; i++)
        {
            printf("%i: fd %i\n", i, fds[i].fd);
        }
        if ((n = poll(fds, nb_fds, TIMEOUT)) == -1) //on attend un event ici
        {
            perror("poll");
            exit(0);
        }

        if (n > 0) //si un event est arrivé
        {
            printf("event occured\n");
            if (fds[0].revents != 0) //event sur le serveur
            {
                printf("We have a new connection.\n");

                //Accept the connection
                lenClient = sizeof infoaddrClient;
                fds[nb_fds].fd = accept(fds[0].fd, (SA *) & infoaddrClient, &lenClient);
                fds[nb_fds].events = POLLIN | POLLHUP;
                fds[nb_fds].revents = 0;

                printf("Connection to %s\n", inet_ntoa(infoaddrClient.sin_addr));
                //Récupération du pseudo du client
                if ((n = read(fds[nb_fds].fd, nickname, MAXLINE - 1)) < 0)
                {
                    printf("read error\n");
                    exit(1);
                }
                nickname[n] = 0;
                nicknames[nb_fds - 1] = (char*) malloc(sizeof (char) *strlen(nickname));
                strcpy(nicknames[nb_fds - 1], nickname);
                sprintf(buff, "Bienvenue sur le chat, %s \n", nicknames[nb_fds - 1]);
                printf("%s", buff);
                if (write(fds[nb_fds].fd, buff, strlen(buff)) != strlen(buff))
                {
                    perror("write error");
                    exit(1);
                }
                //on previent tous le monde de l'arrivée d'un nouveau client sur le channel
                sprintf(buff, "%s joins the channel\n", nicknames[nb_fds - 1]);                
                for (i = 1; i < nb_fds; i++)
                {
                    if (write(fds[i].fd, buff, strlen(buff) != strlen(buff)))
                    {
                        perror("write error");
                        exit(1);
                    }
                }
                nb_fds++;
            }
            else //event du client
            {
                for (i = 1; i < nb_fds; i++)
                {
                    //on cherche qui est le client qui envoi un message
                    if (fds[i].revents != 0)
                    {
                        //on enregistre le message
                        if ((n = read(fds[i].fd, buff, MAXLINE - 1)) < 0)
                        {
                            printf("read error\n");
                            exit(1);
                        }
                        else if (n == 0) //si pas de message deconnection
                        {
                            printf("disconnected\n");
                            exit(0);
                        }
                        buff[n] = '\0';

                        //On envoi le message à tous les autres clients
                        for (j = 1; j < nb_fds; j++)
                        {
                            printf("i = %i, j = %i\n", i, j);
                            if (j != i && strcmp(buff, "") != 0)
                            {
                                sprintf(buff2, "\n\t\t\t%s#~ %s", nicknames[i - 1], buff);
                                printf("-------------\n%s-------------\n", buff2);
                                if (write(fds[j].fd, buff2, strlen(buff2)) != strlen(buff2))
                                {
                                    perror("write error");
                                    exit(1);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

/**********************************************************************
 * Fonction qui initialise le serveur et qui retourne le file descriptor de
 * sa partie listen (entier retourné par la fonction socket())
 */
int myListen()
{
    int listenfd;
    struct sockaddr_in servaddr;
    // Crée un socket internet pour une connection TCP
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Socket error");
        exit(1);
    }
    //Permet la réexecution du socket immédiatement
    int yes = 1;
    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof (yes)) < 0)
    {
        perror("setsockopt");
        close(listenfd);
        return -1;
    }
    // Defini les caractéristiques des clients potentiels
    bzero(&servaddr, sizeof (servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(PORT);
    // Bind to the port
    if (bind(listenfd, (SA*) & servaddr, sizeof (servaddr)))
    {
        perror("bind error");
        exit(1);
    }
    //Ecoute une possible connection sur le port choisi
    if (listen(listenfd, LISTENQ) < 0)
    {
        perror("listen");
        exit(1);
    }
    return listenfd;
}